package zdream.pmfield.stage;

import java.util.List;
import java.util.Objects;

import zdream.pmfield.stage.Timeline.TimelineItem;
import zdream.pmfield.stage.message.FoeLeaveMessage;
import zdream.pmfield.stage.message.TimelineOrderChangeMessage;
import zdream.pmfield.stage.message.TurnStartMessage;

import static org.junit.Assert.*;

/**
 * 它主要检查, {@link Timeline} 里面的次序不会被打乱.
 *
 * @author Zdream
 * @date 2023-12-13
 * @since 0.0.1
 */
public class TimelineChecker {
	public final StageWrapper wrapper;
	private Timeline timeline;
	private List<TimelineItem> items;

	TimelineChecker(StageWrapper wrapper) {
		this.wrapper = Objects.requireNonNull(wrapper);
	}

	public void init() {
		timeline = Objects.requireNonNull(this.wrapper.stage.timeline);
		wrapper.addBasicHandler(TurnStartMessage.class, this::onTurnStart);
		wrapper.addBasicHandler(FoeLeaveMessage.class, this::onFoeLeave);
		wrapper.addBasicHandler(TimelineOrderChangeMessage.class, this::onTimelineUpdated);
	}

	private void onTurnStart(TurnStartMessage message) {
		checkOrder();
	}

	private void onFoeLeave(FoeLeaveMessage message) {
		if (message.reason != FoeLeaveMessage.DepartureReason.FAINT) {
			return;
		}

		items.removeIf(item -> item.asFoe().foe.foe == message.foe);
	}

	private void onTimelineUpdated(TimelineOrderChangeMessage message) {
		items.removeIf(item -> item.asFoe().foe == message.foe);
	}

	private void checkOrder() {
		List<TimelineItem> newOrders = timeline.createOrder()
				.withCount(16)
				.ignoreAction()
				.newTurnOnlyForFoe()
				.build();
		System.out.println("[TimelineChecker] 当前顺序是: " + newOrders);
		if (items == null || items.isEmpty()) {
			items = newOrders;
			return;
		}

		checkOrder(items, newOrders);
		items = newOrders;
	}

	private void checkOrder(List<TimelineItem> expectList0, List<TimelineItem> actualList0) {
		TimelineItem[] actualList = actualList0.toArray(new TimelineItem[0]);
		TimelineItem[] expectList = expectList0.toArray(new TimelineItem[0]);

		String errorText =
				String.format("检查到两个 timeline 不匹配:\n    之前是 %s\n    现在是 %s", expectList0, actualList0);


		int expectIndex = -1; // i
		int actualIndex = -1; // j

		for (int j = 0; j < actualList.length; j++) {
			TimelineItem current = actualList[j];
			assertTrue(current.isForFoe());
			assertTrue(current.asFoe().newTurn);

			for (int i = 0; i < expectList.length; i++) {
				final TimelineItem item = expectList[i];
				assertTrue(item.isForFoe());
				assertTrue(item.asFoe().newTurn);

				if (Math.abs(item.time - current.time) > 0.0001) {
					continue;
				}
				if (item.asFoe().foe == current.asFoe().foe) {
					expectIndex = i;
					break;
				}
			}

			if (expectIndex > 0) {
				actualIndex = j;
				break;
			}
		}
		assertNotEquals(-1, expectIndex);

		// 预期 actualList 就是 expectList 向左平移 expectIndex 格
		int j = actualIndex + 1;
		for (int i = expectIndex + 1; i < expectList.length; i++) {
			final TimelineItem expect = expectList[i];
			assertTrue(expect.isForFoe());

			for (; j < actualList.length; j++) {
				final TimelineItem actual = actualList[j];
				assertTrue(actual.isForFoe());
				if (expect.asFoe().foe == actual.asFoe().foe) {
					assertTrue(errorText, Math.abs(expect.time - actual.time) < 0.0001);
					break;
				}
			}
			++j;

			if (j >= actualList.length) {
				break;
			}
		}
	}
}
